# 使用 do...end
3.times do |i|
  puts "第 #{i+1} 次循环"
end

# 使用 {}
3.times { |i| puts "第 #{i+1} 次循环" }

# 代码块作为参数
def greet
  puts "开始问候"
  yield if block_given?  # yield 执行传入的代码块
  puts "结束问候"
end

greet { puts "你好，Ruby！" }

# 输出:
# 开始问候
# 你好，Ruby！
# 结束问候

# 带参数的代码块
def calculate(a, b)
  puts "计算结果: #{yield(a, b)}"
end

calculate(5, 3) { |x, y| x + y }  # 输出: 计算结果: 8
calculate(5, 3) { |x, y| x * y }  # 输出: 计算结果: 15

# begin-rescue（类似 try-catch）
begin
  # 可能出错的代码
  result = 10 / 0
rescue ZeroDivisionError => e
  # 处理特定错误
  puts "发生除零错误: #{e.message}"
rescue => e
  # 处理其他所有错误
  puts "发生未知错误: #{e.class}: #{e.message}"
else
  # 没有错误时执行
  puts "计算结果: #{result}"
ensure
  # 无论是否出错都会执行
  puts "计算过程结束"
end

# 输出:
# 发生除零错误: divided by 0
# 计算过程结束

# raise（抛出异常）
def check_age(age)
  raise ArgumentError, "年龄不能为负数" if age < 0
  puts "你的年龄是: #{age}"
end

begin
  check_age(-5)
rescue ArgumentError => e
  puts "参数错误: #{e.message}"
end

# 输出: 参数错误: 年龄不能为负数

# ensure（确保执行，类似 finally）
file = nil
begin
  file = File.open("example.txt", "r")
  content = file.read
  puts content
rescue Errno::ENOENT
  puts "文件不存在"
rescue => e
  puts "读取文件出错: #{e.message}"
ensure
  file.close if file
end
# 输出: 文件不存在（如果文件不存在）

# retry（重试）
attempts = 0

begin
  attempts += 1
  puts "尝试第 #{attempts} 次"
  raise "模拟错误" if attempts < 3
rescue
  retry if attempts < 3
  puts "重试次数已达上限"
end

# 输出:
# 尝试第 1 次
# 尝试第 2 次
# 尝试第 3 次
# 重试次数已达上限

# 综合示例
def process_file(filename)
  begin
    File.open(filename) do |file|
      puts "文件内容:"
      file.each_line { |line| puts line }
    end
  rescue Errno::ENOENT
    puts "错误: 文件 #{filename} 不存在"
  rescue => e
    puts "处理文件时出错: #{e.class}: #{e.message}"
  ensure
    puts "文件处理完成"
  end
end

# 测试
process_file("nonexistent.txt")  # 文件不存在的情况
process_file("/etc/passwd")      # 可能没有权限访问的文件
# 输出:
# 错误: 文件 nonexistent.txt 不存在
# 文件处理完成
# 错误: 文件 /etc/passwd 不存在
# 文件处理完成

# 自定义异常
class MyCustomError < StandardError
  def initialize(message = "这是我的自定义错误")
    super
  end
end

begin
  raise MyCustomError.new("自定义错误信息")
rescue MyCustomError => e
  puts "捕获自定义错误: #{e.message}"
end

# 输出: 捕获自定义错误: 自定义错误信息